package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zmj.sy.mom.srv.aps.bean.entity.base.BaseEntity;
import com.zmj.sy.mom.srv.aps.bean.entity.order.*;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.Station;
import com.zmj.sy.mom.srv.aps.bean.entity.third.SinoCamReceiveNestPart;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseIdReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseListResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.search.*;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.utils.PkgUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class SearchService {

    private final ApsOrderMapper apsOrderMapper;
    private final ApsWorkOrderMapper apsWorkOrderMapper;
    private final ApsWorkDetailMapper apsWorkDetailMapper;
    private final SinoCamReceiveNestPartMapper sinoCamReceiveNestPartMapper;
    private final SinoCamReceiveNestPlateMapper sinoCamReceiveNestPlateMapper;
    private final OrderMapper orderMapper;
    private final StationMapper stationMapper;
    private final OrderBomMapper orderBomMapper;


    public BaseListResVo<SearchTreeResVo> tree(BaseIdReqVo reqVo) {

        List<ApsOrder> apsOrders = apsOrderMapper.lambdaQuery()
                .eq(ApsOrder::getOrderId, reqVo.getId())
                .list();

        List<ApsWorkOrder> apsWorkOrders = apsWorkOrderMapper.lambdaQuery()
                .in(ApsWorkOrder::getApsOrderId, apsOrders.stream().map(BaseEntity::getId).collect(Collectors.toList()))
                .list();

        List<SearchTreeResVo> apsOrderList = apsOrders.stream()
                .sorted(Comparator.comparing(ApsOrder::getSeq))
                .map(e -> {
                    SearchTreeResVo rr = new SearchTreeResVo();
                    rr.setId(-e.getId());
                    rr.setPid(null);
                    rr.setMaterName(PkgUtils.gen(e.getSeq()));
                    rr.setTreeType(1);
                    rr.setFinishCount(new BigDecimal(e.getFinishQty()));
                    rr.setTotalCount(new BigDecimal(e.getOrderQty()));
                    rr.setPlanEndDateTime(e.getPlanEndDateTime());
                    return rr;
                })
                .collect(Collectors.toList());

        Map<Integer, SearchTreeResVo> collect = apsOrderList.stream().collect(Collectors.toMap(SearchTreeResVo::getId, Function.identity()));
        List<ApsWorkOrder> collect1 = apsWorkOrders.stream().filter(e -> e.getPid() == null).collect(Collectors.toList());

        for (ApsWorkOrder e : collect1) {
            e.setPid(collect.get(-e.getApsOrderId()).getId());
        }

        List<SearchTreeResVo> apsWorkOrderList = apsWorkOrders.stream()
                .map(e -> {
                    SearchTreeResVo rr = new SearchTreeResVo();
                    rr.setTreeType(2);
                    rr.setId(e.getId());
                    rr.setPid(e.getPid());
                    rr.setMaterCode(e.getPlmId());
                    rr.setMaterName(e.getMaterName());
                    rr.setFinishCount(e.getFinishCount());
                    rr.setTotalCount(e.getOrderCount());
                    rr.setPlanEndDateTime(e.getPlanEndDateTime());
                    return rr;
                })
                .collect(Collectors.toList());

        apsOrderList.addAll(apsWorkOrderList);

        return new BaseListResVo<>(apsOrderList);
    }

    public BaseListResVo<SearchComponentResVo> component(BaseIdReqVo reqVo) {

        LambdaQueryWrapper<ApsWorkOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ApsWorkOrder::getPid, reqVo.getId());
        wrapper.orderByAsc(ApsWorkOrder::getPid);
        wrapper.orderByAsc(ApsWorkOrder::getMaterCode);
        List<ApsWorkOrder> apsWorkOrders = apsWorkOrderMapper.selectList(wrapper);

        List<Integer> ids = apsWorkOrders.stream().map(BaseEntity::getId).filter(e -> !Objects.equals(e, reqVo.getId())).distinct().collect(Collectors.toList());
        if(!ids.isEmpty()){
            List<ApsWorkOrder> list = apsWorkOrderMapper.lambdaQuery().in(ApsWorkOrder::getPid, ids).list();
            if (!list.isEmpty()) {
                List<Integer> collect = list.stream().map(ApsWorkOrder::getPid).distinct().collect(Collectors.toList());
                apsWorkOrders.removeIf(e -> !collect.contains(e.getId()));
            } else {
                apsWorkOrders.clear();
            }
        }

        ApsWorkOrder apsWorkOrder = apsWorkOrderMapper.selectById(reqVo.getId());
        Order order = orderMapper.selectById(apsWorkOrder.getOrderId());

        apsWorkOrders.sort(Comparator.comparing(ApsWorkOrder::getPlmId));
        apsWorkOrders.add(0, apsWorkOrder);

        List<Integer> collect1 = apsWorkOrders.stream().map(ApsWorkOrder::getPid).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<Integer, ApsWorkOrder> parentMap = new HashMap<>();
        if(!collect1.isEmpty()){
            List<ApsWorkOrder> list = apsWorkOrderMapper.lambdaQuery().in(ApsWorkOrder::getId, collect1).list();
            if(CollUtil.isNotEmpty(list)){
                parentMap = list.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
            }
        }
        Map<Integer, ApsWorkOrder> finalParentMap = new HashMap<>(parentMap);

        List<SearchComponentResVo> collect = apsWorkOrders.stream()
                .map(e -> {
                    SearchComponentResVo rr = new SearchComponentResVo();
                    rr.setId(e.getId());
                    rr.setPlanEndDateTime(e.getPlanEndDateTime());
                    rr.setPartCount(e.getPartCount());
                    rr.setOrderCount(e.getOrderCount());
                    rr.setMaterCode(e.getPlmId());
                    rr.setMaterName(e.getMaterName());
                    rr.setWorkChain(e.getWorkChain());
                    rr.setMaterWeight(e.getMaterWeight());
                    rr.setActualEndDateTime(e.getActualEndDateTime());
                    if (e.getPid() != null) {
                        ApsWorkOrder parent = finalParentMap.get(e.getPid());
                        rr.setParentMaterName(parent.getMaterName());
                    }
                    rr.setErpCode(e.getErpCode());
                    rr.setWorkOrderCode(e.getWorkOrderCode());
                    rr.setConstructNo(order.getConstructNo());
                    return rr;
                })
                .collect(Collectors.toList());

        return new BaseListResVo<>(collect);
    }

    public BaseListResVo<SearchPartResVo> part(BaseIdReqVo reqVo) {

        ApsWorkOrder parent11 = apsWorkOrderMapper.selectById(reqVo.getId());
        Order order = orderMapper.selectById(parent11.getOrderId());


        LambdaQueryWrapper<ApsWorkOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ApsWorkOrder::getPid, reqVo.getId());
        wrapper.orderByAsc(ApsWorkOrder::getPid);
        wrapper.orderByAsc(ApsWorkOrder::getMaterCode);
        List<ApsWorkOrder> apsWorkOrders = apsWorkOrderMapper.selectList(wrapper);

        List<Integer> ids = apsWorkOrders.stream().map(BaseEntity::getId).filter(e -> !Objects.equals(e, reqVo.getId())).distinct().collect(Collectors.toList());
        if(!ids.isEmpty()){
            List<ApsWorkOrder> list = apsWorkOrderMapper.lambdaQuery().in(ApsWorkOrder::getPid, ids).list();
            if (!list.isEmpty()) {
                List<Integer> collect = list.stream().map(ApsWorkOrder::getPid).distinct().collect(Collectors.toList());
                apsWorkOrders.removeIf(e -> collect.contains(e.getId()));
            }
        }

        apsWorkOrders.sort(Comparator.comparing(ApsWorkOrder::getPlmId));

        List<Integer> collect1 = apsWorkOrders.stream().map(ApsWorkOrder::getPid).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<Integer, ApsWorkOrder> parentMap = new HashMap<>();
        if(!collect1.isEmpty()){
            List<ApsWorkOrder> list = apsWorkOrderMapper.lambdaQuery().in(ApsWorkOrder::getId, collect1).list();
            if(CollUtil.isNotEmpty(list)){
                parentMap = list.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
            }
        }

        if(CollUtil.isEmpty(apsWorkOrders)){
            return BaseListResVo.empty();
        }

        List<SinoCamReceiveNestPart> list = sinoCamReceiveNestPartMapper.lambdaQuery()
                .in(SinoCamReceiveNestPart::getPartId, apsWorkOrders.stream().map(ApsWorkOrder::getPlmId).collect(Collectors.toList()))
                .list();
        Map<String, SinoCamReceiveNestPart> map = list.stream().collect(Collectors.toMap(SinoCamReceiveNestPart::getPartId, Function.identity(), (e1, e2) -> e1));

        Map<Integer, ApsWorkOrder> finalParentMap = new HashMap<>(parentMap);


        List<SearchPartResVo> collect = apsWorkOrders.stream()
                .map(e -> {
                    SearchPartResVo rr = new SearchPartResVo();
                    rr.setId(e.getId());
                    rr.setPlanEndDateTime(e.getPlanEndDateTime());
                    rr.setPartCount(e.getPartCount());
                    rr.setOrderCount(e.getOrderCount());
                    rr.setMaterCode(e.getPlmId());
                    rr.setMaterName(e.getMaterName());
                    rr.setWorkChain(e.getWorkChain());
                    rr.setMaterWeight(e.getMaterWeight());
                    rr.setActualEndDateTime(e.getActualEndDateTime());
                    if (e.getPid() != null) {
                        ApsWorkOrder parent = finalParentMap.get(e.getPid());
                        rr.setParentMaterName(parent.getMaterName());
                    }

                    SinoCamReceiveNestPart sinoCamReceiveNestPart = map.get(e.getPlmId());
                    if(sinoCamReceiveNestPart == null){
                        rr.setDimension("-");
                    } else {
                        rr.setPlateCode(sinoCamReceiveNestPart.getPlateCode());
                        rr.setDimension(String.format("%s * %s * %s", sinoCamReceiveNestPart.getLength() == null ? "-" : sinoCamReceiveNestPart.getLength(), sinoCamReceiveNestPart.getWidth() == null ? "-" : sinoCamReceiveNestPart.getWidth(), sinoCamReceiveNestPart.getThickness() == null ? "-" : sinoCamReceiveNestPart.getThickness()));
                    }

                    rr.setErpCode(e.getErpCode());
                    rr.setWorkOrderCode(e.getWorkOrderCode());
                    rr.setConstructNo(order.getConstructNo());
                    return rr;
                })
                .collect(Collectors.toList());

        return new BaseListResVo<>(collect);
    }


    public BaseListResVo<SearchPhaseResVo> phase(BaseIdReqVo reqVo) {

        List<ApsWorkDetail> apsWorkDetailList = apsWorkDetailMapper.lambdaQuery()
                .eq(ApsWorkDetail::getApsWorkOrderId, reqVo.getId())
                .list();

        if(apsWorkDetailList.isEmpty()){
            return BaseListResVo.empty();
        }
        List<Integer> collect1 = apsWorkDetailList.stream().map(ApsWorkDetail::getStationId).distinct().collect(Collectors.toList());

        List<Station> stationList = stationMapper.selectBatchIds(collect1);
        Map<Integer, Station> stationMap = stationList.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));

        List<SearchPhaseResVo> collect = apsWorkDetailList.stream()
                .sorted(Comparator.comparing(ApsWorkDetail::getPhaseSeq))
                .map(e -> {
                    SearchPhaseResVo rr = new SearchPhaseResVo();
                    rr.setId(e.getId());
                    rr.setPhaseCode(e.getPhaseCode());
                    rr.setPhaseName(e.getPhaseName());
                    rr.setGroupCode(e.getGroupCode());
                    if (e.getStationId() != null && stationMap.get(e.getStationId()) != null) {
                        rr.setStationCode(stationMap.get(e.getStationId()).getMyCode());
                    }
                    rr.setTotalCount(e.getTotalCount());
                    rr.setFinishCount(e.getFinishCount());
                    rr.setWorkTime(e.getWorkTime());
                    rr.setTotalWorkTime(e.getTotalWorkTime());
                    rr.setPlanStartDateTime(e.getPlanStartDateTime());
                    rr.setPlanEndDateTime(e.getPlanEndDateTime());
                    rr.setActualStartDateTime(e.getActualStartDateTime());
                    rr.setActualEndDateTime(e.getActualEndDateTime());
                    rr.setPhaseSeq(e.getPhaseSeq());
                    return rr;
                })
                .collect(Collectors.toList());

        // 数量汇总
        Map<Integer, SearchPhaseResVo> collect2 = collect.stream().collect(Collectors.toMap(SearchPhaseResVo::getPhaseSeq, e -> e, (e1, e2) -> {
            e1.setTotalCount(e1.getTotalCount().add(e2.getTotalCount()));
            e1.setFinishCount(e1.getFinishCount().add(e2.getFinishCount()));
            // 计划开始时间
            if (e2.getPlanStartDateTime().isBefore(e1.getPlanStartDateTime())) {
                e1.setPlanStartDateTime(e2.getPlanStartDateTime());
            }
            // 计划结束时间
            if (e2.getPlanEndDateTime().isAfter(e1.getPlanEndDateTime())) {
                e1.setPlanEndDateTime(e2.getPlanEndDateTime());
            }

            // 开始时间有不为空的取不为空最小的
            if (e2.getActualStartDateTime() != null) {
                if (e1.getActualStartDateTime() == null || e2.getActualStartDateTime().isBefore(e1.getActualStartDateTime())) {
                    e1.setActualStartDateTime(e2.getActualStartDateTime());
                }
            }


            // 结束时间 全都不为空，取最大，有一个为空，则为空
            if (!Objects.isNull(e1.getActualEndDateTime()) && !Objects.isNull(e2.getActualEndDateTime()) ) {
                if (e2.getActualEndDateTime().isAfter(e1.getActualEndDateTime())) {
                    e1.setActualEndDateTime(e2.getActualEndDateTime());
                }
            } else {
                e1.setActualEndDateTime(null);
            }

            return e1;
        }));
        ArrayList<SearchPhaseResVo> searchPhaseResVos = new ArrayList<>(collect2.values());
        searchPhaseResVos.sort(Comparator.comparing(SearchPhaseResVo::getPhaseSeq));

        return new BaseListResVo<>(searchPhaseResVos);
    }

    public String draw(BaseIdReqVo reqVo) {
        // 根据零件找到钢板
        ApsWorkOrder task = apsWorkOrderMapper.selectById(reqVo.getId());

        String code = null;
        if (task.getPlmId().endsWith("_170")) {
            code = task.getPlmId().substring(0, task.getPlmId().indexOf("_170"));
        } else {
            code = task.getPlmId();
        }

        SinoCamReceiveNestPart nestPart = sinoCamReceiveNestPartMapper.lambdaQuery().eq(SinoCamReceiveNestPart::getPartId, code).last(" limit 1 ").one();

        if(nestPart == null){
            return "";
        }

        return nestPart.getPartMapUrl();
    }

    public BaseListResVo<SearchComponentResVo> packageComponent(BaseIdReqVo reqVo) {

        LambdaQueryWrapper<ApsWorkOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.isNull(ApsWorkOrder::getPid);
        wrapper.eq(ApsWorkOrder::getApsOrderId, - reqVo.getId());
        wrapper.orderByAsc(ApsWorkOrder::getPid);
        wrapper.orderByAsc(ApsWorkOrder::getMaterCode);
        List<ApsWorkOrder> apsWorkOrders = apsWorkOrderMapper.selectList(wrapper);

        List<Integer> ids = apsWorkOrders.stream().map(BaseEntity::getId).distinct().collect(Collectors.toList());
        if(!ids.isEmpty()){
            List<ApsWorkOrder> list = apsWorkOrderMapper.lambdaQuery().in(ApsWorkOrder::getPid, ids).list();
            if (!list.isEmpty()) {
                List<Integer> collect = list.stream().map(ApsWorkOrder::getPid).distinct().collect(Collectors.toList());
                apsWorkOrders.removeIf(e -> !collect.contains(e.getId()));
            } else {
                apsWorkOrders.clear();
            }
        }

        ApsOrder apsOrder = apsOrderMapper.selectById(-reqVo.getId());
        Order order = orderMapper.selectById(apsOrder.getOrderId());

        apsWorkOrders.sort(Comparator.comparing(ApsWorkOrder::getPlmId));

        List<Integer> collect1 = apsWorkOrders.stream().map(ApsWorkOrder::getPid).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<Integer, ApsWorkOrder> parentMap = new HashMap<>();
        if(!collect1.isEmpty()){
            List<ApsWorkOrder> list = apsWorkOrderMapper.lambdaQuery().in(ApsWorkOrder::getId, collect1).list();
            if(CollUtil.isNotEmpty(list)){
                parentMap = list.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
            }
        }
        Map<Integer, ApsWorkOrder> finalParentMap = new HashMap<>(parentMap);

        List<SearchComponentResVo> collect = apsWorkOrders.stream()
                .map(e -> {
                    SearchComponentResVo rr = new SearchComponentResVo();
                    rr.setId(e.getId());
                    rr.setPlanEndDateTime(e.getPlanEndDateTime());
                    rr.setPartCount(e.getPartCount());
                    rr.setOrderCount(e.getOrderCount());
                    rr.setMaterCode(e.getPlmId());
                    rr.setMaterName(e.getMaterName());
                    rr.setWorkChain(e.getWorkChain());
                    rr.setMaterWeight(e.getMaterWeight());
                    rr.setActualEndDateTime(e.getActualEndDateTime());
                    if (e.getPid() != null) {
                        ApsWorkOrder parent = finalParentMap.get(e.getPid());
                        rr.setParentMaterName(parent.getMaterName());
                    }
                    rr.setErpCode(e.getErpCode());
                    rr.setWorkOrderCode(e.getWorkOrderCode());
                    rr.setConstructNo(order.getConstructNo());
                    return rr;
                })
                .collect(Collectors.toList());

        return new BaseListResVo<>(collect);
    }

    public BaseListResVo<SearchPartResVo> packagePart(BaseIdReqVo reqVo) {

        ApsOrder apsOrder = apsOrderMapper.selectById(- reqVo.getId());
        Order order = orderMapper.selectById(apsOrder.getOrderId());
        LambdaQueryWrapper<ApsWorkOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ApsWorkOrder::getApsOrderId, - reqVo.getId());
        wrapper.orderByAsc(ApsWorkOrder::getPid);
        wrapper.orderByAsc(ApsWorkOrder::getMaterCode);
        List<ApsWorkOrder> apsWorkOrders = apsWorkOrderMapper.selectList(wrapper);

        List<Integer> ids = apsWorkOrders.stream().map(BaseEntity::getId).filter(e -> !Objects.equals(e, reqVo.getId())).distinct().collect(Collectors.toList());
        if(!ids.isEmpty()){
            List<ApsWorkOrder> list = apsWorkOrderMapper.lambdaQuery().in(ApsWorkOrder::getPid, ids).list();
            if (!list.isEmpty()) {
                List<Integer> collect = list.stream().map(ApsWorkOrder::getPid).distinct().collect(Collectors.toList());
                apsWorkOrders.removeIf(e -> collect.contains(e.getId()));
            }
        }

        apsWorkOrders.sort(Comparator.comparing(ApsWorkOrder::getLevel));

        List<Integer> collect1 = apsWorkOrders.stream().map(ApsWorkOrder::getPid).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<Integer, ApsWorkOrder> parentMap = new HashMap<>();
        if(!collect1.isEmpty()){
            List<ApsWorkOrder> list = apsWorkOrderMapper.lambdaQuery().in(ApsWorkOrder::getId, collect1).list();
            if(CollUtil.isNotEmpty(list)){
                parentMap = list.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
            }
        }

        if(CollUtil.isEmpty(apsWorkOrders)){
            return BaseListResVo.empty();
        }

        List<SinoCamReceiveNestPart> list = sinoCamReceiveNestPartMapper.lambdaQuery()
                .in(SinoCamReceiveNestPart::getPartId, apsWorkOrders.stream().map(ApsWorkOrder::getPlmId).collect(Collectors.toList()))
                .list();
        Map<String, SinoCamReceiveNestPart> map = list.stream().collect(Collectors.toMap(SinoCamReceiveNestPart::getPartId, Function.identity(), (e1, e2) -> e1));

        Map<Integer, ApsWorkOrder> finalParentMap = new HashMap<>(parentMap);

        List<SearchPartResVo> collect = apsWorkOrders.stream()
                .map(e -> {
                    SearchPartResVo rr = new SearchPartResVo();
                    rr.setId(e.getId());
                    rr.setPlanEndDateTime(e.getPlanEndDateTime());
                    rr.setPartCount(e.getPartCount());
                    rr.setOrderCount(e.getOrderCount());
                    rr.setMaterCode(e.getPlmId());
                    rr.setMaterName(e.getMaterName());
                    rr.setWorkChain(e.getWorkChain());
                    rr.setMaterWeight(e.getMaterWeight());
                    rr.setActualEndDateTime(e.getActualEndDateTime());
                    if (e.getPid() != null) {
                        ApsWorkOrder parent = finalParentMap.get(e.getPid());
                        rr.setParentMaterName(parent.getMaterName());
                    }

                    SinoCamReceiveNestPart sinoCamReceiveNestPart = map.get(e.getPlmId());
                    if(sinoCamReceiveNestPart == null){
                        rr.setDimension("-");
                    } else {
                        rr.setDimension(String.format("%s * %s * %s", sinoCamReceiveNestPart.getLength() == null ? "-" : sinoCamReceiveNestPart.getLength(), sinoCamReceiveNestPart.getWidth() == null ? "-" : sinoCamReceiveNestPart.getWidth(), sinoCamReceiveNestPart.getThickness() == null ? "-" : sinoCamReceiveNestPart.getThickness()));
                    }


                    rr.setErpCode(e.getErpCode());
                    rr.setWorkOrderCode(e.getWorkOrderCode());
                    rr.setConstructNo(order.getConstructNo());
                    return rr;
                })
                .collect(Collectors.toList());

        return new BaseListResVo<>(collect);
    }

    public BaseListResVo<SearchFindResVo> find(SearchFindReqVo reqVo) {

        if (StringUtils.isBlank(reqVo.getPlmid())) {
            return null;
        }

        // 查询符合条件的零件
        List<OrderBom> list = orderBomMapper.lambdaQuery()
                .eq(OrderBom::getOrderId, reqVo.getOrderId())
                .eq(OrderBom::getPlmId, reqVo.getPlmid())
                .list();

        // 查询父级零件，获取父级物料名称
        for (OrderBom orderBom : list) {
            if (orderBom.getPid() == null) {
                String father = orderBom.getMaterName();
                orderBom.setMaterName(father);
                continue;
            }
            OrderBom order = orderBomMapper.lambdaQuery()
                    .eq(OrderBom::getId, orderBom.getPid())
                    .one();
            orderBom.setMaterName(order.getMaterName());
        }

        return BaseListResVo.of(list, SearchFindResVo.class);

    }

}
